﻿using Org.BouncyCastle.Asn1.Ocsp;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace QQZiFramework
{
    public class MyHttpUtility
    {
        private SecurityProtocolType securityProtocolType = SecurityProtocolType.Tls12;


        Encoding encoding = Encoding.UTF8;
        private HttpWebResponse webResponse;
        protected string mainUrl = null;
        protected string backupUrl = null;
        public int RequestTimeout = 60000;
        public NameValueCollection DefaultHeader = new NameValueCollection();
        public bool Expect100Continue { get; set; }

        /// <summary>
        /// 是否检禁止输入返回内容到日志
        /// </summary>
        public bool NotLogResponse { get; set; }

        /// <summary>
        /// 获取cookie的值
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public string GetCookieValue(Uri uri, string name)
        {
            Cookie c = GetCookie(uri, name);
            if (c != null) return c.Value;
            return null;
        }

        public Cookie GetCookie(Uri uri, string name)
        {

            CookieCollection collection = globalCookieContainer.GetCookies(uri);
            foreach (Cookie c in collection)
            {
                if (c.Name == name) return c;
            }
            return null;
        }

        public void AddCookie(Cookie c)
        {
            globalCookieContainer.Add(c);
        }
        public HttpWebResponse GeteLastResponse()
        {
            return webResponse;
        }
        public Encoding TextEncoding { get { return encoding; } set { encoding = value; } }

        public SecurityProtocolType SecurityProtocolType
        {
            get { return securityProtocolType; }
            set { securityProtocolType = value; }
        }

        /// <summary>
        /// 默认证书路径
        /// </summary>
        public static string DefaultCertificatePath { get; set; }

        public string Identity = Guid.NewGuid().ToString();

        /// <summary>
        /// 本次证书路径，空则使用默认
        /// </summary>
        public string CertificatePath { get; set; }

        /// <summary>
        /// 本次证书密码
        /// </summary>
        public string CertificatePwd { get; set; }

        public MyHttpUtility(DBContext context,int timeoutSecond=0)
        {
            m_context = context;
            CertificatePath = DefaultCertificatePath;
            if(timeoutSecond >0) RequestTimeout = timeoutSecond * 1000;
        }

        public MyHttpUtility()
        {
            CertificatePath = DefaultCertificatePath;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="host">远程主机地址，会在后台自动加/</param>
        public MyHttpUtility(string host)
        {
            mainUrl = host;
            if (host[host.Length - 1] != '/') mainUrl += "/";
            CertificatePath = DefaultCertificatePath;
        }
        public MyHttpUtility(string host, Encoding encoding)
        {
            mainUrl = host;
            if (host != null && host[host.Length - 1] != '/') mainUrl += "/";
            this.encoding = encoding;
            CertificatePath = DefaultCertificatePath;
        }
        public MyHttpUtility(string host, SecurityProtocolType sptype, Encoding encoding)
        {
            mainUrl = host;
            if (host != null && host[host.Length - 1] != '/') mainUrl += "/";
            securityProtocolType = sptype;
            this.encoding = encoding;
            CertificatePath = DefaultCertificatePath;
        }

        public MyHttpUtility(string host, SecurityProtocolType sptype, Encoding encoding, string CertFile)
        {
            mainUrl = host;
            if (host != null && host[host.Length - 1] != '/') mainUrl += "/";
            securityProtocolType = sptype;
            this.encoding = encoding;
            CertificatePath = CertFile;
        }

        private const string DefaultUserAgent = "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1";

        public string UserAgent { get; set; }

        private string GetUserAgent()
        {
            return UserAgent == null ? DefaultUserAgent : UserAgent;
        }

        private void BugFix_CookieDomain(CookieCollection collection)
        {

            foreach (Cookie c in collection)
            {
                if (c.Domain[0] != '.' && c.Domain.LastIndexOf('.') == c.Domain.IndexOf('.'))
                {
                    c.Domain = "." + c.Domain;
                }
                c.HttpOnly = false;
                c.Path = "/";

            }
        }

        private String GetMid(String input, String s, String e)
        {
            int pos = input.IndexOf(s);
            if (pos == -1)
            {
                return "";
            }

            pos += s.Length;


            int pos_end = 0;
            if (e == "")
            {
                pos_end = input.Length;
            }
            else
            {
                pos_end = input.IndexOf(e, pos);
            }


            if (pos_end == -1)
            {
                return "";
            }
            return input.Substring(pos, pos_end - pos);
        }

        public virtual String DoGet(String url, bool reandomNum = true)
        {
            return DoGet(url, null, reandomNum, null);
        }
        public virtual String DoGet(String url, string referer, bool reandomNum = true)
        {
            return DoGet(url, null, reandomNum, referer);
        }
        //public String DoGet(String url, string referer,string contentType, bool reandomNum = true)
        //{
        //    return DoGet(url,contentType, reandomNum, referer);
        //}


        protected CookieContainer globalCookieContainer = new CookieContainer();
        /// <summary>
        /// 代理设置
        /// </summary>
        public IWebProxy Proxy { get; set; }
        private CookieContainer SetHostCookie(Uri uri, CookieCollection cookies)
        {
            BugFix_CookieDomain(cookies);
            globalCookieContainer.Add(cookies);
            return globalCookieContainer;
        }

        /// <summary>
        /// 获取主地址（结果为：http[s]://www.domain.com）
        /// </summary>
        private Uri getCookieUri(Uri uri)
        {
            int pos = uri.AbsoluteUri.IndexOf('/', 8);
            if (pos == -1) return uri;
            else return new Uri(uri.AbsoluteUri.Substring(0, pos));
        }

        public static CookieCollection GetAllCookies(CookieContainer cc)
        {
            CookieCollection lstCookies = new CookieCollection();
            Hashtable table = (Hashtable)cc.GetType().InvokeMember("m_domainTable", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance, null, cc, new object[] { });
            foreach (object pathList in table.Values)
            {
                SortedList lstCookieCol = (SortedList)pathList.GetType().InvokeMember("m_list", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance, null, pathList, new object[] { });
                foreach (CookieCollection colCookies in lstCookieCol.Values)
                    foreach (Cookie c in colCookies) lstCookies.Add(c);
            }
            return lstCookies;
        }

        private CookieContainer GetHostCookieContainer(Uri uri)
        {
            System.Diagnostics.Debug.WriteLine("-------------------" + uri.Authority + "---------------");
            CookieCollection coll = globalCookieContainer.GetCookies(uri);
            foreach (Cookie c in coll)
            {
                System.Diagnostics.Debug.WriteLine(string.Format("Name:{0}  value:{1}  domain:{2} path:{3}", c.Name, c.Value, c.Domain, c.Path));
            }
            CookieContainer cc = new CookieContainer();
            cc.Add(uri, coll);
            return cc;
        }

        public bool CertificateValidationRewrite = true;

        private HttpWebRequest CreateHttpsRequest(String actionUrl, string certificate)
        {
            if (mainUrl != null && !actionUrl.StartsWith("http")) actionUrl = mainUrl + actionUrl;
            HttpWebRequest webReqst = WebRequest.Create(actionUrl) as HttpWebRequest;
            if (actionUrl.StartsWith("https", StringComparison.OrdinalIgnoreCase) && CertificateValidationRewrite)
            {
                ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult);
                ServicePointManager.SecurityProtocol = securityProtocolType;
                webReqst.ProtocolVersion = HttpVersion.Version10;
                //创建证书文件
                if (certificate == null)
                {
                    if (CertificatePath == null) CertificatePath = DefaultCertificatePath;
                    certificate = CertificatePath;
                    // if (certificate == null) throw new ClientException("未指定https证书，请设置CertificatePath或者DefaultCertificatePath");
                }
                //if (certificate.Length < 4 || certificate.IndexOf(':', 1, 2) == -1) certificate = DefaultCertificatePath + "\\" + certificate;
                if (certificate != null)
                {
                    if (Path.GetExtension(certificate) == null) certificate = Path.Combine(certificate, "123.cer");
                    if (!File.Exists(certificate)) throw new Exception("证书文件不存在:" + certificate);
                    X509Certificate objx509;
                    if (CertificatePwd == null)
                        objx509 = new X509Certificate(certificate);
                    else
                        objx509 = new X509Certificate2(certificate, CertificatePwd);
                    webReqst.ClientCertificates.Add(objx509);
                }
            }
            webReqst.Proxy = Proxy;
            webReqst.UserAgent = GetUserAgent();
            webReqst.KeepAlive = true;
            //webReqst.Timeout = RequestTimeout;
            webReqst.ReadWriteTimeout = RequestTimeout;
            webReqst.ContentType = "application/x-www-form-urlencoded";
            webReqst.CookieContainer = GetHostCookieContainer(new Uri(actionUrl));
            if (Expect100Continue) webReqst.ServicePoint.Expect100Continue = Expect100Continue;
            if (DefaultHeader != null && DefaultHeader.Count > 0) webReqst.Headers.Add(DefaultHeader);
            return webReqst;
        }
        public String DoGet(String actionUrl, string contentType, bool reandomNum, string referer)
        {
            return DoGet(actionUrl, contentType, reandomNum, referer, null, null);
        }



        /// <param name="actionUrl"></param>
        /// <param name="contentType"></param>
        /// <param name="reandomNum"></param>
        /// <param name="referer"></param>
        /// <param name="cookies"></param>
        /// <param name="autoRedirect">自动跳转（Response.Redirect），默认为true</param>
        /// <returns></returns>
        /// <summary>
        /// Get方式访问
        /// </summary>
        /// <param name="actionUrl"></param>
        /// <param name="contentType"></param>
        /// <param name="reandomNum"></param>
        /// <param name="referer"></param>
        /// <param name="cookies"></param>
        /// <param name="autoRedirect">自动跳转（Response.Redirect），默认为true</param>
        /// <returns></returns>
        public String DoGet(String actionUrl, string contentType, bool reandomNum, string referer, NameValueCollection heads, CookieContainer cookies, bool autoRedirect = true, byte[] data = null)
        {
            if (mainUrl != null && !actionUrl.StartsWith("http")) actionUrl = mainUrl + actionUrl;
            if (reandomNum) actionUrl = UrlAddRandom(actionUrl);
            String html = "";
            StreamReader reader = null;
            HttpWebRequest webReqst;
            Uri uri = new Uri(actionUrl);
            //if (uri.AbsolutePath.IndexOf(".") == -1 && uri.AbsoluteUri.IndexOf("?")==-1 && uri.PathAndQuery.LastIndexOf('/') < 1) actionUrl += "/";
            webReqst = CreateHttpsRequest(actionUrl, null);
            webReqst.Method = "GET";
            webReqst.AllowAutoRedirect = autoRedirect;// false;
            if (cookies != null) webReqst.CookieContainer = cookies;
            if (contentType != null) webReqst.ContentType = contentType;
            if (referer != null)
            {
                if (mainUrl != null) referer = mainUrl + referer;
                webReqst.Referer = referer;
            }
            if (heads != null && heads.Count > 0) webReqst.Headers.Add(heads);
            if (data != null && data.Length > 0)
            {
                webReqst.ContentLength = data.Length;
                Stream stream = webReqst.GetRequestStream();
                stream.Write(data, 0, data.Length);
            }
            if (m_context != null) m_context.LogMessage(webReqst.RequestUri.ToString(), "HTTP");
            GetResponse(webReqst);
            if (webResponse.Cookies.Count > 0) SetHostCookie(uri, webResponse.Cookies);
            if (webResponse.StatusCode == HttpStatusCode.OK || webResponse.StatusCode == HttpStatusCode.Redirect)
            {
                Stream stream = webResponse.GetResponseStream();
                //stream.ReadTimeout = RequestTimeout;
                if (webResponse.ContentEncoding == "gzip")
                {
                    reader = new StreamReader(new GZipStream(stream, CompressionMode.Decompress), encoding);
                }
                else
                {
                    reader = new StreamReader(stream, encoding);
                }
                html = reader.ReadToEnd();
                if (DebugLog && !NotLogResponse)
                {
                    m_context.LogMessage(html, "HTTP");
                }
            }
            else
            {
                //MovedPermanently 跳转
                if (webResponse.StatusCode != HttpStatusCode.MovedPermanently) throw new Exception("server error:" + webResponse.StatusCode);
            }
            //string location = webResponse.GetResponseHeader("Location");
            //if (!string.IsNullOrEmpty(location))
            //{
            //    int pos = actionUrl.LastIndexOf('/');
            //    if (!location.ToLower().StartsWith("http"))
            //    {

            //        location = actionUrl.Substring(0, pos + 1) + location;
            //    }
            //    if (actionUrl.Contains("artifact"))
            //    { }
            //    else
            //    {
            //        html = DoGet(location, null, false, null, cookies);
            //    }
            //}
            return html;
        }

        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true; //总是接受  
        }


        /// <summary>
        /// HttpUploadFile
        /// </summary>
        /// <param name="url"></param>
        /// <param name="files"></param>
        /// <param name="data"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public string Upload(string url, byte[] data, string fileName)
        {
            if (fileName == null) fileName = "temp.jpg";
            string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
            byte[] boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
            byte[] endbytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");

            //1.HttpWebRequest
            HttpWebRequest request = this.CreateHttpsRequest(url, null);
            request.ContentType = "multipart/form-data; boundary=" + boundary;
            request.Method = "POST";
            request.KeepAlive = true;
            request.Credentials = CredentialCache.DefaultCredentials;

            using (Stream stream = request.GetRequestStream())
            {

                //1.2 file
                string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n";
                byte[] buffer = new byte[4096];
                //int bytesRead = 0;
                // for (int i = 0; i < files.Length; i++)
                // {
                stream.Write(boundarybytes, 0, boundarybytes.Length);
                string header = string.Format(headerTemplate, "file0", fileName);
                byte[] headerbytes = encoding.GetBytes(header);
                stream.Write(headerbytes, 0, headerbytes.Length);
                stream.Write(data, 0, data.Length);
                // }

                //1.3 form end
                stream.Write(endbytes, 0, endbytes.Length);
            }
            //2.WebResponse
            GetResponse(request);
            using (StreamReader stream = new StreamReader(webResponse.GetResponseStream()))
            {
                return stream.ReadToEnd();
            }
        }



        public void Download(string actionUrl, string savePath, string certificate = null, string referer = null)
        {
            string directoryName = Path.GetDirectoryName(savePath);
            if (!Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); }
            HttpWebRequest webRequest = CreateHttpsRequest(actionUrl, certificate);
            //添加到请求里             
            //webRequest.Accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*";
            //webRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322)";
            //webRequest.ContentType = "application/x-www-form-urlencoded";
            webRequest.Method = "GET";
            //webRequest.Headers.Add("Accept-Language", "zh-cn");
            //webRequest.Headers.Add("Accept-Encoding", "gzip,deflate");
            webRequest.KeepAlive = true;
            if (referer != null) { webRequest.Referer = mainUrl != null ? mainUrl + referer : referer; }
            //获取服务器返回的资源  
            GetResponse(webRequest);
            if (webResponse.Cookies.Count > 0) SetHostCookie(new Uri(actionUrl), webResponse.Cookies);
            using (Stream sream = webResponse.GetResponseStream())
            {
                List<byte> list = new List<byte>();
                while (true)
                {
                    int data = sream.ReadByte();
                    if (data == -1)
                        break;
                    list.Add((byte)data);
                }
                File.WriteAllBytes(savePath, list.ToArray());
            }
        }

        public byte[] DownloadBytes(string actionUrl, string certificateRoot, string referer = null)
        {
            if (mainUrl != null && !actionUrl.StartsWith("http")) actionUrl = mainUrl + actionUrl;
            Uri uri = new Uri(actionUrl);
            HttpWebRequest webRequest = CreateHttpsRequest(actionUrl, certificateRoot);
            //属性配置   
            webRequest.AllowWriteStreamBuffering = true;
            //webRequest.MaximumResponseHeadersLength = -1;
            //webRequest.Accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*";
            //webRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322)";
            //webRequest.ContentType = "application/x-www-form-urlencoded";
            webRequest.Method = "GET";
            //webRequest.Headers.Add("Accept-Language", "zh-cn");
            //webRequest.Headers.Add("Accept-Encoding", "gzip,deflate");
            webRequest.KeepAlive = true;
            if (referer != null) { webRequest.Referer = mainUrl != null ? mainUrl + referer : referer; }
            //获取服务器返回的资源   
            byte[] bytes;
            GetResponse(webRequest);
            if (webResponse.Cookies.Count > 0) SetHostCookie(uri, webResponse.Cookies);
            using (Stream sream = webResponse.GetResponseStream())
            {
                List<byte> list = new List<byte>();
                while (true)
                {
                    int data = sream.ReadByte();
                    if (data == -1)
                        break;
                    list.Add((byte)data);
                }
                bytes = list.ToArray();
            }
            return bytes;
        }


        public string UrlAddRandom(string url)
        {
            Random r = new Random();
            int randomNum = r.Next(100000, 999999);
            var randomPar = "randomNum=" + randomNum;
            int pos = url.IndexOf("?");
            if (pos > 0)
            {
                if (pos != url.Length - 1) url += "&" + randomPar;
                else url = randomPar;
            }
            else url += "?" + randomPar;
            return url;
        }
        public String DoPost(String url, string data)
        {
            byte[] dataBytes = encoding.GetBytes(data);
            return DoPost(url, dataBytes, null, null, null, null);
        }
        public String DoPost(String url, string data, string contentType)
        {
            byte[] dataBytes = encoding.GetBytes(data);
            return DoPost(url, dataBytes, contentType, null, null, null);
        }
        public String DoPost(String url, byte[] data)
        {
            return DoPost(url, data, null, null, null);
        }
        public String DoPost(String url, string strData, string contentType, NameValueCollection heads, string referer, bool autoRedirect = true)
        {
            byte[] bytes = null;
            if (!string.IsNullOrEmpty(strData))
            {
                bytes = encoding.GetBytes(strData);
            }
            return DoPost(url, bytes, contentType, heads, referer, null, autoRedirect);
        }

        public String DoPost(String url, byte[] data, string contentType, NameValueCollection heads, string referer)
        {
            return DoPost(url, data, contentType, heads, referer, null);
        }

        public String DoPut(String url, byte[] data, string contentType, NameValueCollection heads, string referer)
        {
            return DoPost(url, data, contentType, heads, referer, null,true,"PUT");
        }

        public String DoPost(String url, byte[] data, string contentType, NameValueCollection heads, string referer, CookieContainer cookies, bool autoRedirect = true,string method= "POST")
        {
            if (mainUrl != null && !url.StartsWith("http"))
            {
                if (url[0] == '/') url = url.Substring(1);
                url = mainUrl + url;
            }
            Uri uri = new Uri(url);
            string html = "";
            StreamReader reader = null;
            HttpWebRequest webReqst = CreateHttpsRequest(url, null);
            if (referer != null)
            {
                if (mainUrl != null) referer = mainUrl + referer;
                webReqst.Referer = referer;
            }
            if (contentType != null) webReqst.ContentType = contentType;
            webReqst.Method = method;
            if (cookies != null) webReqst.CookieContainer = cookies;
            webReqst.AllowAutoRedirect = autoRedirect;

            if (heads != null && heads.Count > 0) webReqst.Headers.Add(heads);
            if (data != null)
            {
                webReqst.ContentLength = data.Length;
                webReqst.GetRequestStream().Write(data, 0, data.Length);
            }
            bool logRequestData = DebugLog;
            if (logRequestData && heads != null) logRequestData = heads["Content-Disposition"] == null;
            if (logRequestData) logRequestData = webReqst.RequestUri.PathAndQuery.IndexOf("/UploadImage") == -1;
            if (m_context != null) m_context.LogMessage(webReqst.RequestUri.ToString(), "HTTP");
            if (data != null && logRequestData && m_context != null)
            {
                m_context.LogMessage(encoding.GetString(data), "HTTP");
            }
            string location = url;
            GetResponse(webReqst);
            if (webResponse.Cookies.Count > 0)
            {
                cookies = SetHostCookie(uri, webResponse.Cookies);
            }
            if ((webResponse.StatusCode == HttpStatusCode.OK || webResponse.StatusCode == HttpStatusCode.Redirect || webResponse.StatusCode == HttpStatusCode.Created))
            {
                Stream stream = webResponse.GetResponseStream();
                //stream.ReadTimeout = RequestTimeout;
                if (webResponse.ContentEncoding == "gzip")
                {
                    reader = new StreamReader(new GZipStream(stream, CompressionMode.Decompress), encoding);
                }
                else
                {
                    reader = new StreamReader(stream, encoding);
                }
                html = reader.ReadToEnd();
                if (DebugLog && !NotLogResponse)
                {
                    m_context.LogMessage(html, "HTTP");
                }
            }
            else
            {
                //MovedPermanently 跳转
                if (webResponse.StatusCode != HttpStatusCode.MovedPermanently) throw new Exception("server error:" + webResponse.StatusCode);
            }
            //location = webResponse.GetResponseHeader("Location");
            //if (!string.IsNullOrEmpty(location))
            //{
            //    if (!location.ToLower().StartsWith("http"))
            //    {
            //        int pos = url.LastIndexOf('/');
            //        location = url.Substring(0, pos + 1) + location;
            //    }
            //    html = DoGet(location, null, false, null, cookies);
            //}
            return html;
        }
        public void DoGetAsync(String actionUrl, string contentType, NameValueCollection heads, Action<int, string> callback)
        {
            if (mainUrl != null && !actionUrl.StartsWith("http")) actionUrl = mainUrl + actionUrl;
            //if (reandomNum) actionUrl = UrlAddRandom(actionUrl);
            String html = "";
            StreamReader reader = null;
            HttpWebRequest webReqst;
            Uri uri = new Uri(actionUrl);
            //if (uri.AbsolutePath.IndexOf(".") == -1 && uri.AbsoluteUri.IndexOf("?")==-1 && uri.PathAndQuery.LastIndexOf('/') < 1) actionUrl += "/";
            webReqst = CreateHttpsRequest(actionUrl, null);
            webReqst.Method = "GET";
            // webReqst.AllowAutoRedirect = autoRedirect;// false;
            // if (cookies != null) webReqst.CookieContainer = cookies;
            if (contentType != null) webReqst.ContentType = contentType;
            // if (referer != null)
            // {
            //     if (mainUrl != null) referer = mainUrl + referer;
            //     webReqst.Referer = referer;
            // }
            if (heads != null && heads.Count > 0) webReqst.Headers.Add(heads);
            // if (data != null && data.Length > 0)
            // {
            //     webReqst.ContentLength = data.Length;
            //     Stream stream = webReqst.GetRequestStream();
            //     stream.Write(data, 0, data.Length);
            // }
            if (m_context != null) m_context.LogMessage(webReqst.RequestUri.ToString(), "HTTP");
            webReqst.ReadWriteTimeout = 90000;
            webReqst.BeginGetResponse(new AsyncCallback(OnAsyncResponse), new AsyncStateObject { Callback = callback, Request = webReqst });
        }
        public void DoPostAsync(String url, byte[] data, string contentType, NameValueCollection heads, Action<int, string> callback)
        {
            if (mainUrl != null && !url.StartsWith("http"))
            {
                if (url[0] == '/') url = url.Substring(1);
                url = mainUrl + url;
            }
            Uri uri = new Uri(url);
            string html = "";
            StreamReader reader = null;
            HttpWebRequest webReqst = CreateHttpsRequest(url, null);
            // if (referer != null)
            // {
            //     if (mainUrl != null) referer = mainUrl + referer;
            //     webReqst.Referer = referer;
            // }
            if (contentType != null) webReqst.ContentType = contentType;
            webReqst.Method = "POST";
            //if (cookies != null) webReqst.CookieContainer = cookies;
            //webReqst.AllowAutoRedirect = autoRedirect;

            if (heads != null && heads.Count > 0) webReqst.Headers.Add(heads);
            if (data != null)
            {
                webReqst.ContentLength = data.Length;
                webReqst.GetRequestStream().Write(data, 0, data.Length);
            }
            bool logRequestData = DebugLog;
            if (logRequestData && heads != null) logRequestData = heads["Content-Disposition"] == null;
            if (logRequestData) logRequestData = webReqst.RequestUri.PathAndQuery.IndexOf("/UploadImage") == -1;
            if (m_context != null) m_context.LogMessage(webReqst.RequestUri.ToString(), "HTTP");
            if (data != null && logRequestData && m_context != null)
            {
                m_context.LogMessage(encoding.GetString(data), "HTTP");
            }
            webReqst.ReadWriteTimeout = 90000;
            webReqst.BeginGetResponse(new AsyncCallback(OnAsyncResponse), new AsyncStateObject { Callback = callback, Request = webReqst });
        }

        void OnAsyncResponse(IAsyncResult ar)
        {
            if (System.Net.ServicePointManager.DefaultConnectionLimit < 3)
            {
                Console.WriteLine("异步请求，最好设置请求并发数System.Net.ServicePointManager.DefaultConnectionLimit大于2");
            }
            AsyncStateObject obj = ar.AsyncState as AsyncStateObject;
            HttpWebResponse webResponse = null;
            try
            {
                webResponse = obj.Request.EndGetResponse(ar) as HttpWebResponse;
            }
            catch (Exception ex)
            {
                obj.Callback(-1, ex.Message);
                return;
            }
            // if (webResponse.Cookies.Count > 0)
            // {
            //     SetHostCookie(obj.Request.RequestUri, webResponse.Cookies);
            // }
            if ((webResponse.StatusCode == HttpStatusCode.OK || webResponse.StatusCode == HttpStatusCode.Redirect || webResponse.StatusCode == HttpStatusCode.Created))
            {
                Stream stream = webResponse.GetResponseStream();
                StreamReader reader;
                if (webResponse.ContentEncoding == "gzip")
                {
                    reader = new StreamReader(new GZipStream(stream, CompressionMode.Decompress), encoding);
                }
                else
                {
                    reader = new StreamReader(stream, encoding);
                }
                var html = reader.ReadToEnd();
                if (DebugLog && !NotLogResponse)
                {
                    m_context.LogMessage(html, "HTTP");
                }
                obj.Callback((int)webResponse.StatusCode, html);
            }
            else
            {
                //MovedPermanently 跳转
                if (webResponse.StatusCode != HttpStatusCode.MovedPermanently)
                {
                    obj.Callback((int)webResponse.StatusCode, "server error");
                }
            }
        }

        public String DoDelete(String url, byte[] data, string contentType, NameValueCollection heads = null)
        {
            if (mainUrl != null && !url.StartsWith("http"))
            {
                if (url[0] == '/') url = url.Substring(1);
                url = mainUrl + url;
            }
            Uri uri = new Uri(url);
            string html = "";
            StreamReader reader = null;
            HttpWebRequest webReqst = CreateHttpsRequest(url, null);
            webReqst.Method = "DELETE";
            if(contentType!=null) webReqst.ContentType = contentType;   
            if (heads != null && heads.Count > 0) webReqst.Headers.Add(heads);
            if (data != null)
            {
                using (Stream requestStream = webReqst.GetRequestStream())
                {
                    requestStream.Write(data, 0, data.Length);
                    requestStream.Close();
                }
                webReqst.ContentLength = data.Length;
            }
            if (DebugLog)
            {
                m_context.LogMessage(webReqst.RequestUri.ToString(), "HTTP DELETE");
            }
            string location = url;
            GetResponse(webReqst);

            if (webResponse.StatusCode == HttpStatusCode.OK)
            {
                System.IO.Stream stream = webResponse.GetResponseStream();
                if (webResponse.ContentEncoding == "gzip")
                {
                    reader = new StreamReader(new GZipStream(stream, CompressionMode.Decompress), encoding);
                }
                else
                {
                    reader = new StreamReader(stream, encoding);
                }
                html = reader.ReadToEnd();
                if (DebugLog && !NotLogResponse)
                {
                    m_context.LogMessage(html, "HTTP");
                }
            }
            else
            {
                throw new Exception("server error:" + webResponse.StatusCode);
            }
            return html;
        }

        DBContext m_context;

        public bool DebugLog
        {
            get
            {
                if (m_context != null)
                {
                    return m_context.GetSettingValue<bool>("Modules:http:DebugLog", false, false);
                }
                else
                    return false;
            }
        }
        public void GetResponse(HttpWebRequest webReqst)
        {
            int tryCount = 10;
            while (tryCount > 0)
            {
                try
                {
                    webResponse = (HttpWebResponse)webReqst.GetResponse();
                    break;
                }
                catch (System.Net.WebException ex)
                {

                    if (tryCount == 1) throw ex;
                    System.Threading.Thread.Sleep(3000);
                    if (ex.Message.IndexOf("无法连接到") == -1 && ex.Message.IndexOf("The remote name could not be resolved") == -1 && ex.Message.IndexOf("Unable to connect to the remote server") == -1)
                    {
                        if (ex.Response != null && ex.Response.GetResponseStream() != null)
                        {
                            StreamReader reader = new StreamReader(ex.Response.GetResponseStream(), encoding);
                            string html = reader.ReadToEnd();
                            if (m_context != null) m_context.LogMessage(html, "HTTP");

                        }
                        throw ex;
                    }
                    tryCount--;
                    if (tryCount == 5)
                    {
                        if (String.IsNullOrEmpty(backupUrl))
                            tryCount = 1;
                        else
                        {
                            webReqst.Host = backupUrl.Substring(7, backupUrl.Length - 8);
                        }
                    }
                }
            }

        }


        public class AsyncStateObject
        {
            public Action<int, string> Callback { get; set; }
            public HttpWebRequest Request { get; set; }
        }
    }

}
